/* Copyright (c) 2008 Google Inc.
*  Copyright (c) 2009 Pierre Henri Kuate.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace SerializationTests
{

public abstract class IData
{
}
public class ResultItem
{
    public string id { get; set; }
    public IData data { get; set; }
}
public class Name
{
    public string familyName { get; set; }
    public string givenName { get; set; }
}
public class Photo
{
    public string value { get; set; }
    public string type { get; set; }
}
public class Person : IData
{
    public string id { get; set; }
    public bool isViewer { get; set; }
    public string thumbnailUrl { get; set; }
    public Name name { get; set; }
    public bool isOwner { get; set; }
    public System.Collections.Generic.IList<Photo> photos { get; set; }
}
public class SearchResult : IData
{
    public int startIndex { get; set; }
    public int totalResults { get; set; }
    public System.Collections.Generic.IList<IData> list { get; set; }
}

public static class Serialization
{
    public enum ResultType
    {
        Single,
        Multiple,
    }
    public class BatchResult
    {
        public BatchResult(ResultType resultType, System.Type elementType)
        {
            ResultType = resultType;
            ElementType = elementType;
        }
        public readonly ResultType ResultType;
        public readonly System.Type ElementType;
    }
    public class DataContractSurrogate : System.Runtime.Serialization.IDataContractSurrogate
    {
        private const int MagicNumber = -1730;
        public int Index;
        public int MultipleReturned;
        public int Depth;
        private readonly BatchResult[] _results;

        public DataContractSurrogate(params BatchResult[] results)
        {
            _results = results;
            Reset();
        }

        public void Reset()
        {
            Index = 0;
            Depth = -1730;
            ResetMultipleReturned();
        }

        private void ResetMultipleReturned()
        {
            MultipleReturned = (_results.Length > Index && _results[Index].ResultType == ResultType.Multiple) ? 0 : -1;
        }

        public System.Type GetDataContractType(System.Type type)
        {
            if (type == typeof(IData))
            {
                if (_results[Index].ResultType == ResultType.Multiple)
                {
                    if (MultipleReturned == 0)
                    {
                        Depth = 0;
                        MultipleReturned = 1;
                        return typeof(SearchResult);
                    }
                    if (MultipleReturned == 1)
                    {
                        Depth++;
                        return _results[Index].ElementType;
                    }
                    throw new System.Exception("TODO");
                }
                Depth = 0;
                return _results[Index].ElementType;
            }
            Depth++;
            return type;
        }

        public object GetObjectToSerialize(object obj, System.Type targetType)
        {
            if (!targetType.IsAssignableFrom(obj.GetType()))
                throw new System.Exception("TODO: Shouldn't happen");
            Depth--;
            if (Depth == -1) // End of the ResultItem
            {
                Depth = MagicNumber;
                Index++; // Move to the next
                ResetMultipleReturned();
            }
            return obj;
        }

        public object GetDeserializedObject(object obj, System.Type targetType)
        {
            if (!targetType.IsAssignableFrom(obj.GetType()))
                throw new System.Exception("TODO: Shouldn't happen");
            Depth--;
            if (Depth == -1) // End of the ResultItem
            {
                Depth = MagicNumber;
                Index++; // Move to the next
                ResetMultipleReturned();
            }
            return obj;
        }

        public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, System.Type dataContractType)
        {
            return null;
        }

        public object GetCustomDataToExport(System.Type clrType, System.Type dataContractType)
        {
            return null;
        }

        public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<System.Type> customDataTypes)
        {
            customDataTypes.ToString();
        }

        public System.Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
        {
            return null;
        }

        public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
        {
            return typeDeclaration;
        }
    }

    /// <summary>
    /// Experimenting using System.Runtime.Serialization.Json.DataContractJsonSerializer.
    /// The goal is to be able to use POCO classes.
    /// </summary>
    public static void Run()
    {
        const string BatchViewerAndFriends =
@"[
{""id"":""person0"",""data"":
    {""photos"":[{""value"":""http://www.orkut.com/img/i_nophoto64.gif"",""type"":""thumbnail""}],
    ""id"":""03067092798963641994"",""isViewer"":true,""thumbnailUrl"":""http://www.orkut.com/img/i_nophoto64.gif"",""name"":{""familyName"":""DWH"",""givenName"":""API""},""isOwner"":false}
},
{""id"":""person1"",""data"":
    {""photos"":[{""value"":""http://www.orkut.com/img/i_nophoto64.gif"",""type"":""thumbnail""}],
    ""id"":""03067092798963641994"",""isViewer"":true,""thumbnailUrl"":""http://www.orkut.com/img/i_nophoto64.gif"",""name"":{""familyName"":""DWH"",""givenName"":""API""},""isOwner"":false}
},
{""id"":""friends2"",""data"":
    {""startIndex"":0,""totalResults"":6,
    ""list"":[
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/1195663673/115231346.jpg"",""type"":""thumbnail""}],
            ""id"":""13314698784882897227"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/1195663673/115231346.jpg"",""name"":{""familyName"":""Roomann-Kurrik"",""givenName"":""Arne""},""isOwner"":false},
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/1192668331/105202920.jpg"",""type"":""thumbnail""}],
            ""id"":""04285289033838943214"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/1192668331/105202920.jpg"",""name"":{""familyName"":""Holevoet"",""givenName"":""Dan""},""isOwner"":false},
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/119/119.jpg"",""type"":""thumbnail""}],
            ""id"":""02529645406784203776"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/119/119.jpg"",""name"":{""familyName"":""Joslin"",""givenName"":""Jeremy""},""isOwner"":false},
        {""photos"":[{""value"":""http://www.orkut.com/img/i_nophoto64.gif"",""type"":""thumbnail""}],
            ""id"":""13289573027306639609"",""isViewer"":false,""thumbnailUrl"":""http://www.orkut.com/img/i_nophoto64.gif"",""name"":{""familyName"":""Nolan"",""givenName"":""John""},""isOwner"":false},
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/650/1297650.jpg"",""type"":""thumbnail""}],
            ""id"":""10689077536072106193"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/650/1297650.jpg"",""name"":{""familyName"":""Koushik"",""givenName"":""Manoj""},""isOwner"":false},
        {""photos"":[{""value"":""http://www.orkut.com/img/i_nophoto64.gif"",""type"":""thumbnail""}],
            ""id"":""04054380375212606745"",""isViewer"":false,""thumbnailUrl"":""http://www.orkut.com/img/i_nophoto64.gif"",""name"":{""familyName"":""boyd"",""givenName"":""ryan""},""isOwner"":false}
    ]}
},
{""id"":""person3"",""data"":
    {""photos"":[{""value"":""http://www.orkut.com/img/i_nophoto64.gif"",""type"":""thumbnail""}],
    ""id"":""03067092798963641994"",""isViewer"":true,""thumbnailUrl"":""http://www.orkut.com/img/i_nophoto64.gif"",""name"":{""familyName"":""DWH"",""givenName"":""API""},""isOwner"":false}
},
{""id"":""friends4"",""data"":
    {""startIndex"":0,""totalResults"":6,
    ""list"":[
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/1195663673/115231346.jpg"",""type"":""thumbnail""}],
            ""id"":""13314698784882897227"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/1195663673/115231346.jpg"",""name"":{""familyName"":""Roomann-Kurrik"",""givenName"":""Arne""},""isOwner"":false},
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/1192668331/105202920.jpg"",""type"":""thumbnail""}],
            ""id"":""04285289033838943214"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/1192668331/105202920.jpg"",""name"":{""familyName"":""Holevoet"",""givenName"":""Dan""},""isOwner"":false},
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/119/119.jpg"",""type"":""thumbnail""}],
            ""id"":""02529645406784203776"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/119/119.jpg"",""name"":{""familyName"":""Joslin"",""givenName"":""Jeremy""},""isOwner"":false},
        {""photos"":[{""value"":""http://www.orkut.com/img/i_nophoto64.gif"",""type"":""thumbnail""}],
            ""id"":""13289573027306639609"",""isViewer"":false,""thumbnailUrl"":""http://www.orkut.com/img/i_nophoto64.gif"",""name"":{""familyName"":""Nolan"",""givenName"":""John""},""isOwner"":false},
        {""photos"":[{""value"":""http://img2.orkut.com/images/small/650/1297650.jpg"",""type"":""thumbnail""}],
            ""id"":""10689077536072106193"",""isViewer"":false,""thumbnailUrl"":""http://img2.orkut.com/images/small/650/1297650.jpg"",""name"":{""familyName"":""Koushik"",""givenName"":""Manoj""},""isOwner"":false},
        {""photos"":[{""value"":""http://www.orkut.com/img/i_nophoto64.gif"",""type"":""thumbnail""}],
            ""id"":""04054380375212606745"",""isViewer"":false,""thumbnailUrl"":""http://www.orkut.com/img/i_nophoto64.gif"",""name"":{""familyName"":""boyd"",""givenName"":""ryan""},""isOwner"":false}
    ]}
}
]";
        var dcSurrogate = new DataContractSurrogate(
            new BatchResult(ResultType.Single, typeof(Person)),
            new BatchResult(ResultType.Single, typeof(Person)),
            new BatchResult(ResultType.Multiple, typeof(Person)),
            new BatchResult(ResultType.Single, typeof(Person)),
            new BatchResult(ResultType.Multiple, typeof(Person))/**/
            );
        var deserializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(System.Collections.Generic.List<ResultItem>),
            "root", null,//new System.Collections.Generic.List<System.Type> { typeof(ResultItem), typeof(Person), typeof(Name), typeof(Photo) },
            int.MaxValue, false, dcSurrogate, true);

        var o = deserializer.ReadObject(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(BatchViewerAndFriends)));

        /*var stream = new System.IO.MemoryStream(); // TODO: Doesn't work (yet) + After, remove the "__type=XXX" & all elements with the default value (eg: null)
        dcSurrogate.Reset();
        deserializer.WriteObject(stream, o);
        stream.Position = 0;
        var reader = new System.IO.StreamReader(stream);
        var json = reader.ReadToEnd();/**/


        var p = new Person {
            id = "03067092798963641994", isViewer = true,
            thumbnailUrl = "http://www.orkut.com/img/i_nophoto64.gif",
            name = new Name { familyName = "DWH", givenName = "API" }, isOwner = false,
            photos = new System.Collections.Generic.List<Photo> { new Photo { value = "http://www.orkut.com/img/i_nophoto64.gif", type = "thumbnail" } }
        /**/};

        var stream = new System.IO.MemoryStream();
        var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Person),
            "root", new System.Collections.Generic.List<System.Type> { typeof(Name) },
            int.MaxValue, false, new DataContractSurrogate(), true);
        serializer.WriteObject(stream, p);

        stream.Position = 0;
        var reader = new System.IO.StreamReader(stream);
        var json2 = reader.ReadToEnd();

        const string xJson = "{\"id\":\"03067092798963641994\",\"isOwner\":false,\"isViewer\":true,\"name\":{\"familyName\":\"DWH\",\"givenName\":\"API\"},\"photos\":[{\"type\":\"thumbnail\",\"value\":\"http:\\/\\/www.orkut.com\\/img\\/i_nophoto64.gif\"}],\"thumbnailUrl\":\"http:\\/\\/www.orkut.com\\/img\\/i_nophoto64.gif\"}";
        bool equal = xJson == json2;
        var p2 = serializer.ReadObject(new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(xJson)));/**/

        return;
    }
}


}
